/*
 * Copyright (c) 2025 EasyAdmin
 * All rights reserved.
 *
 * This file is part of the [EasAdmin] project.
 * Unauthorized copying of this file, via any medium, is strictly prohibited.
 * Proprietary and confidential.
 *
 * Author: EasyAdmin ( 1073602@qq.com )
 * Website: https://www.xhxiao.com
 */
package com.easy.framework.security.aspectj;

import com.easy.framework.common.model.BaseQuery;
import com.easy.framework.common.utils.Func;
import com.easy.framework.common.utils.StringUtil;
import com.easy.framework.security.annotation.DataScope;
import com.easy.framework.security.enums.DataScopeEnum;
import com.easy.framework.security.model.LoginUser;
import com.easy.framework.security.model.Role;
import com.easy.framework.security.utils.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.stream.Collectors;

/**
 * 数据范围切片
 *
 * @author EasyAdmin ( 1073602@qq.com )
 * @date 2025-08-20
 */
@Aspect
@Component
public class DataScopeAspect {

    @Before("@annotation(dataScope)")
    public void doBefore(JoinPoint point, DataScope dataScope) throws Throwable {
        Object obj = point.getArgs()[0];
        if (Func.isNotEmpty(obj) && obj instanceof BaseQuery) {
            BaseQuery query = (BaseQuery) obj;
            query.clearDateScope();
            LoginUser loginUser = SecurityUtils.getUser();
            if (Func.isNotEmpty(loginUser) && !SecurityUtils.isAdmin(loginUser.getUserId())) {
                dataScopeFilter(dataScope, loginUser, query);
            }
        }
    }

    /**
     * 数据范围过滤器
     *
     * @param dataScope 数据范围
     * @param loginUser 登录用户
     */
    public static void dataScopeFilter(final DataScope dataScope, LoginUser loginUser, BaseQuery query) {
        StringBuilder sql = new StringBuilder();
        boolean isAll = false;
        for (Role role : loginUser.getRoles()) {
            String roleDataScope = role.getDataScope();
            if (DataScopeEnum.ALL.getValue().equals(roleDataScope)) {
                isAll = true;
                break;
            } else if (DataScopeEnum.DEPT.getValue().equals(roleDataScope)) {
                if (Func.isNotEmpty(dataScope.deptAlias())) {
                    if (loginUser.getDepts().size() > 1) {
                        String inVal = loginUser.getDepts().stream().map(d -> String.valueOf(d.getDeptId())).collect(Collectors.joining(","));
                        sql.append(StringUtil.format(" OR {}.{} IN ({}) ", dataScope.deptAlias(), dataScope.deptIdName(), inVal));
                    } else {
                        long deptId = loginUser.getDepts().get(0).getDeptId();
                        sql.append(StringUtil.format(" OR {}.{} = {} ", dataScope.deptAlias(), dataScope.deptIdName(), deptId));
                    }
                } else if (Func.isNotEmpty(dataScope.userAlias())) {
                    if (role.getDeptIds().size() > 1) {
                        String inVal = loginUser.getDepts().stream().map(d -> String.valueOf(d.getDeptId())).collect(Collectors.joining(","));
                        sql.append(StringUtil.format(" OR {}.{} IN (select distinct user_id from sys_user_dept ud join sys_dept d on  ud.dept_id = d.id WHERE d.id in ({})) ", dataScope.userAlias(), dataScope.userIdName(), inVal));
                    } else if (role.getDeptIds().size() == 1) {
                        sql.append(StringUtil.format(" OR {}.{} IN (select user_id from sys_user_dept where dept_id = {}) ", dataScope.userAlias(), dataScope.userIdName(), role.getDeptIds().get(0)));
                    }
                }
            } else if (DataScopeEnum.DEPT_CHILD.getValue().equals(roleDataScope)) {
                if (Func.isNotEmpty(dataScope.deptAlias())) {
                    if (loginUser.getDepts().size() > 1) {
                        String rVal = loginUser.getDepts().stream().map(d -> String.valueOf(d.getDeptId())).collect(Collectors.joining("|"));
                        sql.append(StringUtil.format(
                                " OR {}.{} IN (SELECT dept_id FROM sys_dept WHERE dept_id ({}) or (ancestors REGEXP  '\\\\b({})\\\\b'))",
                                dataScope.deptAlias(), dataScope.deptIdName(), rVal.replaceAll("|", ","), rVal));
                    } else {
                        long deptId = loginUser.getDepts().get(0).getDeptId();
                        sql.append(StringUtil.format(
                                " OR {}.{} IN (SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set({}, ancestors))",
                                dataScope.deptAlias(), dataScope.deptIdName(), deptId, deptId));
                    }
                } else if (Func.isNotEmpty(dataScope.userAlias())) {
                    if (role.getDeptIds().size() > 1) {
                        String rVal = loginUser.getDepts().stream().map(d -> String.valueOf(d.getDeptId())).collect(Collectors.joining("|"));
                        sql.append(StringUtil.format(" OR {}.{} IN (select distinct user_id from sys_user_dept ud join sys_dept d on  ud.dept_id = d.id WHERE d.id ({}) or (d.ancestors REGEXP  '\\\\b({})\\\\b')) ", dataScope.userAlias(), dataScope.userIdName(), rVal.replaceAll("|", ","), rVal));
                    } else if (role.getDeptIds().size() == 1) {
                        sql.append(StringUtil.format(" OR {}.{} IN (select user_id from sys_user_dept where dept_id = {}) ", dataScope.userAlias(), dataScope.userIdName(), role.getDeptIds().get(0)));
                    }
                }
            } else if (DataScopeEnum.CUSTOM.getValue().equals(roleDataScope)) {
                if (Func.isNotEmpty(dataScope.deptAlias())) {
                    if (role.getDeptIds().size() > 1) {
                        String inVal = role.getDeptIds().stream().map(String::valueOf).collect(Collectors.joining(","));
                        sql.append(StringUtil.format(" OR {}.{} IN ({}) ", dataScope.deptAlias(), dataScope.deptIdName(), inVal));
                    } else if (role.getDeptIds().size() == 1) {
                        sql.append(StringUtil.format(" OR {}.{} = {} ", dataScope.deptAlias(), dataScope.deptIdName(), role.getDeptIds().get(0)));
                    }
                } else if (Func.isNotEmpty(dataScope.userAlias())) {
                    if (role.getDeptIds().size() > 1) {
                        String inVal = role.getDeptIds().stream().map(String::valueOf).collect(Collectors.joining(","));
                        sql.append(StringUtil.format(" OR {}.{} IN (select user_id from sys_user_dept where dept_id in ({})) ", dataScope.userAlias(), dataScope.userIdName(), inVal));
                    } else if (role.getDeptIds().size() == 1) {
                        sql.append(StringUtil.format(" OR {}.{} IN (select user_id from sys_user_dept where dept_id = {}) ", dataScope.userAlias(), dataScope.userIdName(), role.getDeptIds().get(0)));
                    }
                }
            } else if (DataScopeEnum.SELF.getValue().equals(roleDataScope)) {
                sql.append(StringUtil.format(" OR {}.{} = {} ", dataScope.userAlias(), dataScope.userIdName(), loginUser.getUserId()));
            }
        }
        if (!isAll && Func.isNotEmpty(query)) {
            if (Func.isEmpty(sql.toString())) {
                sql.append(" AND 1 != 1");
            }
            query.setDataScope(sql.substring(4));
        }
    }

}
